Ambiten Release

Ambiten Core v1.2.4 — Context Binding and Runtime Resolution Refinements

Ambiten Core v1.2.4 sharpens the boundaries between execution context, model operations, database providers, tenant infrastructure, client resolution, and transaction participation.

Ambiten Core v1.2.4 is a runtime refinement release focused on making execution behavior more explicit. It strengthens the relationship between AmbitenContext, ModelContext, AmbitenModel, AmbitenSchema, AmbitenClient, tenant infrastructure, and transactions while keeping the application-facing programming model approachable.

The work behind this release is not about adding complexity for its own sake. It is about making the existing runtime easier to reason about as Ambiten moves between direct MongoDB usage and more advanced multi-tenant, transaction-aware systems.

A central part of that work has been clarifying which layer owns which responsibility.

Context carries execution. Models bind execution to operations. Infrastructure determines where those operations run.

A Clearer Runtime Model

One of the most important refinements in v1.2.4 is a clearer distinction between full execution state and model-operation state.

AmbitenContext carries the state associated with an active execution. That may include tenant identity, request identity, database scope, transaction sessions, logging metadata, instrumentation state, and runtime controls.

AmbitenContextState
        ↓
AmbitenContext
        ↓
Application Logic
        ↓
AmbitenModel
        ↓
Effective ModelContext
        ↓
Schema / Middleware
        ↓
Infrastructure Resolution
        ↓
AmbitenClient
        ↓
MongoDB

ModelContext serves a different purpose. It represents the persistence-facing state required by a particular model operation.

Rather than asking every schema, middleware function, or database provider to reconstruct the active runtime context independently, AmbitenModel creates one effective operation context.


From AmbitenContext To ModelContext

During model execution, Ambiten resolves the effective ModelContext using a deterministic precedence.

explicit operation context
        ↓
active AmbitenContext
        ↓
model defaults
        ↓
Effective ModelContext

This means execution state can be established once at the runtime boundary and then carried naturally into persistence operations.

A model operation such as:

await UserModel.find({});

can participate in tenant-aware or transaction-aware execution without requiring every service in the application to manually forward tenant identifiers, request identifiers, database names, or MongoDB sessions.

The distinction is simple:

AmbitenContextState
= full execution-scoped state

ModelContext
= model-operation-facing state

They are not competing context systems. ModelContext is the persistence-facing projection of the execution state required by the model runtime.


AmbitenClient Remains A First-Class Direct API

AmbitenClient has also received clearer positioning in the runtime architecture.

It should not be thought of only as an internal component hidden beneath AmbitenModel.

Direct use remains intentional:

Application
    ↓
AmbitenClient
    ↓
MongoDB

This makes Ambiten suitable for small applications, scripts, educational examples, live coding sessions, migrations, internal tooling, and direct database workflows.

As an application grows, the same client can participate beneath the model runtime:

AmbitenContext
      ↓
AmbitenModel
      ↓
Effective ModelContext
      ↓
DbProvider
      ↓
AmbitenClient
      ↓
MongoDB

That progressive model is deliberate. A developer does not need to understand the complete multi-tenant runtime before performing a useful database operation.

Start directly. Add structure when the application needs it.

More Explicit Database Resolution

AmbitenClient database resolution now has a clearly documented order.

1. Explicit ctx.db

2. Tenant-aware resolution

3. Explicit ctx.dbName

4. Mutable database override

5. Configured or default database

This keeps explicit operation state authoritative while still supporting tenant-aware infrastructure and configured defaults.

For tenant-aware execution, AmbitenClient can resolve the correct MongoDB client through its configured tenant resolver.

ModelContext.tenantId
      ↓
Tenant Client Resolver
      ↓
MongoClient
      ↓
Tenant Database

The application does not need to know how that client was discovered, registered, or activated.


Tenant Identity And Tenant Infrastructure Stay Separate

v1.2.4 continues to reinforce an important architectural separation in Ambiten.

TenantResolver
→ identifies the tenant

AmbitenContext
→ carries tenant identity

MultiTenantManager
→ owns tenant infrastructure

AmbitenClient
→ provides MongoDB capability

Resolving a tenant from an HTTP header, token, subdomain, queue message, or custom resolver is not the same thing as resolving the MongoDB resources that belong to that tenant.

Keeping those responsibilities separate allows MultiTenantManager to handle registered tenants, dynamic discovery, lazy activation, client reuse, and tenant runtime state independently from the framework request.


Scoped Client Execution

AmbitenClient continues to support explicit infrastructure scopes.

const tenantClient =
  client.withTenant("tenant-a");

const reportingClient =
  client.withDatabase("reporting");

const scopedClient =
  client.withScope({
    tenantId: "tenant-a",
    dbName: "reporting"
  });

These APIs create scoped provider views over the base client rather than unrelated MongoDB connection pools.

Explicit operation context remains authoritative where supplied, while the predefined scope acts as a fallback for the scoped client.

The older mutable database switching path remains available through useDatabase(), but scoped client APIs provide a safer model for concurrent and request-aware applications.


Transaction State Follows The Execution

Transaction handling is another area where responsibility is now documented more precisely.

Transaction Boundary
      ↓
ClientSession
      ↓
AmbitenContext.session
      ↓
AmbitenModel
      ↓
ModelContext.session
      ↓
Participating Operations

The transaction boundary owns the transaction lifecycle.

start
commit
rollback
completion

Models participate in the active transaction. They do not independently commit or roll back the surrounding transaction.

This allows application services to remain free from manual MongoDB session plumbing while still giving the runtime a clear atomic boundary.


Two Ways To Establish Transaction Boundaries

Ambiten supports both explicit workflow transactions and adapter-managed execution-wide transactions.

A focused application workflow can use:

await AmbitenContext.withTransaction(
  async () => {
    await UserModel.create({
      name: "Alice"
    });

    await WalletModel.create({
      balance: 0
    });
  }
);

An adapter can instead establish a transaction around the supported execution lifecycle:

enableTransactions: true

These are alternative transaction boundaries rather than two layers that every application must combine.

The important rule remains that participating Ambiten operations share the active transaction session. Arbitrary raw MongoDB calls or external services should not be assumed to join that transaction automatically.


Schema Behavior Is Static, Execution Is Dynamic

AmbitenSchema also fits more clearly into the refined runtime model.

The schema defines structure and persistence-oriented behavior:

document structure
validation
normalization
middleware
soft-delete policy
lifecycle configuration
persistence behavior

Runtime state reaches schema and middleware behavior through the effective ModelContext created for the model operation.

AmbitenContext
      ↓
AmbitenModel
      ↓
Effective ModelContext
      ↓
AmbitenSchema / Middleware

The schema itself does not become tenant-specific or request-specific.

Static definition. Dynamic execution.

One Request, End To End

The accompanying documentation now follows a request through the runtime with the same responsibility boundaries used internally by Ambiten.

HTTP Request
      ↓
Adapter
      ↓
Adapter Runtime
      ↓
Tenant Resolution
      ↓
AmbitenContext
      ↓
Application Handler
      ↓
AmbitenModel
      ↓
Effective ModelContext
      ↓
Schema / Middleware
      ↓
Infrastructure Resolution
      ↓
AmbitenClient
      ↓
MongoDB
      ↓
Result
      ↓
Transaction Completion if active
      ↓
Framework Response

The goal is not to make a simple request look complicated. The goal is to make the hidden responsibilities visible so that each layer remains understandable as the application grows.


Clearer Responsibility Boundaries

The architecture in v1.2.4 can be summarized through a few focused responsibilities.

Adapter
→ execution ingress

TenantResolver
→ tenant identity

AmbitenContext
→ execution state

AmbitenModel
→ operation coordination and context binding

ModelContext
→ persistence-facing operation state

AmbitenSchema
→ structure and persistence behavior

DbProvider
→ database, client, and session contract

MultiTenantManager
→ tenant infrastructure

AmbitenClient
→ MongoDB capability

Transaction Boundary
→ transaction lifecycle

MongoDB
→ persistence

Keeping these boundaries explicit is important because Ambiten is intended to support both approachable direct usage and more demanding runtime architectures.


Reusable Infrastructure, Isolated Execution

Another important distinction is the difference between process-level resources and execution-level state.

PROCESS LIFETIME

AmbitenRuntime
AmbitenClient
MongoClient
MultiTenantManager
providers
runtime configuration
EXECUTION LIFETIME

AmbitenContext
tenantId
requestId
dbName
collectionName
session
logger metadata
runtime metadata

A MongoDB connection can be reused across many executions while tenant identity, request identity, transaction state, and runtime metadata remain isolated to the execution that created them.

This is one of the foundations that allows the same Ambiten runtime to serve concurrent workloads without turning reusable infrastructure into request-specific mutable state.


Progressive Adoption Remains Important

Ambiten is strongest when applications begin to require structured runtime behavior, but the framework was not designed to make that architecture a prerequisite for getting started.

A developer can begin here:

AmbitenClient
      ↓
MongoDB

Then introduce context:

AmbitenContext
      ↓
AmbitenClient / Application

Then reusable schema and model structure:

AmbitenSchema
      ↓
AmbitenModel

And eventually:

Framework Adapters
MultiTenantManager
Dynamic Tenants
Transactions
Middleware
Instrumentation
Runtime Orchestration

Applications can adopt the amount of structure that matches their actual requirements.


Documentation Updated With The Runtime

Alongside the Core release, several areas of the Ambiten documentation have been revised so that the public architecture matches the runtime more precisely.

The updates cover AmbitenClient, Schema, Context, Context Binding, Transactions, Provider responsibilities, ModelContext propagation, multi-tenant infrastructure, and the complete One Request Flow.

A particular focus has been removing ambiguous language around:

execution state
vs
operation state

tenant identity
vs
tenant infrastructure

transaction ownership
vs
transaction participation

model responsibility
vs
provider responsibility

direct client usage
vs
model-runtime usage

Clear terminology becomes increasingly important as a runtime grows. The architecture should not only work. Developers should be able to understand why it works and where each responsibility belongs.


Installing Ambiten Core v1.2.4

The release is available through the @ambiten/core package.

pnpm add @ambiten/core@1.2.4

or:

npm install @ambiten/core@1.2.4

Moving Forward

Ambiten Core v1.2.4 is a refinement release, but the boundaries it clarifies are important for where the runtime is heading.

Context should describe an execution without becoming application data. Models should coordinate persistence operations without owning infrastructure lifecycle. Tenant identity should remain separate from tenant infrastructure. Transactions should preserve atomicity without forcing session objects throughout business code.

And direct MongoDB access should remain approachable even when the same runtime is capable of supporting substantially more advanced systems.

Context carries execution. Model binds execution to an operation. Infrastructure determines where it runs. MongoDB performs persistence.

That is the runtime model Ambiten Core v1.2.4 continues to make clearer.